<?php
/**
 * Клас для роботи з проектом
 *
 * @author ihor
 */
class Project extends Zend_Form 
{
    protected $_date;
    const STATUS_SCAN_DIRECTORIES = '[SCAN_DIRECTORIES]';
    const STATUS_SCAN_FILES       = '[SCAN_FILES]';
    const STATUS_SCAN_CLASSES     = '[SCAN_CLASSES]';
    const STATUS_SCAN_METHODS     = '[SCAN_METHODS]';
    
    /**
     *
     * @var Zend_Config 
     */
    public $config;
    protected $_directory;
    protected $_fileName;
    protected $_frameworks = array(
        'none'      => 'Other',
        'zend'      => 'Zend Framework',
        'symphony'  => 'Symphony',
        'vii'       => 'Vii'
    );
    protected $_testsFrameworks = array(
        'phpunit'   => 'PHPUnit'
    );
    protected $_dbAdapters = array(
        'mysql' => 'MySql',
        'pgsql' => 'PostreSQL'
    );
    
    /**
     * конструктор (якщо є файл - завантажуються данні з нього)
     * @param string $directory директорія проеків
     * @param string $fileName ім’я файлу проекту
     */
    public function __construct($directory, $fileName = '') {
        parent::__construct();
        if (!file_exists($directory))
            throw new Exception("Директорія {$directory} не існує");

        $this->_directory = $directory;
        if ($fileName == '' || !file_exists($fileName)) {
            $this->_date = date('Y-m-d');
        }
        else {
            $this->_fileName = $fileName;
            $this->_load($fileName);
        }
    }
    
    /**
     * завантажує дані з файлу у поля форми
     * @param string $fileName 
     */
    protected function _load($fileName) {
        $config = new Zend_Config_Xml($fileName);
        $this->config = $config;
        $this->_date = $config->date;
        $this->name->setValue($config->name);
        $this->alias->setValue($config->alias);
        $this->projectPath->setValue($config->project->path);
        $this->framework->setValue($config->project->framework);
        $this->testsPath->setValue($config->tests->path);
        $this->testsFramework->setValue($config->tests->framework);
        $this->dbAdapter->setValue($config->db->adapter);
        $this->dbHost->setValue($config->db->host);
        $this->dbUsername->setValue($config->db->username);
        $this->dbPassword->setValue($config->db->password);
    }
    
    /**
     * Повертає доступні фреймворки
     * @return array
     */
    protected function _getFrameworks() {
        return $this->_frameworks;
    }
    
    /**
     * Повертає доступні фреймворки для тестування
     * @return array
     */
    protected function _getTestsFrameworks() {
        return $this->_testsFrameworks;
    }

    /**
     * Повертає доступні адаптери БД
     * @return array
     */
    protected function _getDbAdapters() {
        return $this->_dbAdapters;
    }
    
    /**
     * повертає дату проекту
     * @return string
     */
    public function getDate() {
        return $this->_date;
    }

    /**
     * ініціалізація форми
     */
    public function init() {
        $name = new Zend_Form_Element_Text('name');
        $name->setLabel('[PROJECT_NAME]')
             ->setRequired(true);
        $this->addElement($name);

        $alias = new Zend_Form_Element_Text('alias');
        $alias->setLabel('[PROJECT_ALIAS]')
              ->setRequired(true);
        $this->addElement($alias);
        
        $projectPath = new Zend_Form_Element_Text('projectPath');
        $projectPath->setLabel('[PROJECT_PATH]')
                    ->setRequired(true);
        $this->addElement($projectPath);

        $testsPath = new Zend_Form_Element_Text('testsPath');
        $testsPath->setLabel('[PROJECT_TESTS_PATH]')
                  ->setRequired(true);
        $this->addElement($testsPath);
        
        $testsFramework = new Zend_Form_Element_Hidden('testsFramework');
        $testsFramework->setValue('phpunit');
        $this->addElement($testsFramework);
        
        $framework = new Zend_Form_Element_Select('framework');
        $framework->setLabel('[PROJECT_FRAMEWORK]')
                  ->setMultiOptions($this->_getFrameworks())
                  ->setRequired(true);
        $this->addElement($framework);
 
        $dbAdapter = new Zend_Form_Element_Select('dbAdapter');
        $dbAdapter->setLabel('[PROJECT_DB_ADAPTER]')
                  ->setMultiOptions($this->_getDbAdapters())
                  ->setRequired(true);
        $this->addElement($dbAdapter);

        $dbHost = new Zend_Form_Element_Text('dbHost');
        $dbHost->setLabel('[PROJECT_DB_HOST]')
               ->setRequired(true);
        $this->addElement($dbHost);

        $dbUsername = new Zend_Form_Element_Text('dbUsername');
        $dbUsername->setLabel('[PROJECT_DB_USERNAME]')
                   ->setRequired(true);
        $this->addElement($dbUsername);

        $dbPassword = new Zend_Form_Element_Text('dbPassword');
        $dbPassword->setLabel('[PROJECT_DB_PASSWORD]');
        $this->addElement($dbPassword);

        $dbTest = new Zend_Form_Element_Button('dbTest');
        $dbTest->setLabel('[PROJECT_DB_TEST]');
        $this->addElement($dbTest);

        $submit = new Zend_Form_Element_Submit('submit');
        $submit->setLabel('[PROJECT_SUBMIT]');
        $this->addElement($submit);
        
        $this->addDisplayGroup(array(
                                    'name',
                                    'alias',
                                    'projectPath',
                                    'testsPath',
                                    //'testsFramework',
                                    'framework'),
                               'general',
                               array('decorators' => array('FormElements')));
        $this->addDisplayGroup(array('dbAdapter',
                                     'dbHost',
                                     'dbUsername',
                                     'dbPassword',
                                     'dbTest'),
                               'db',
                               array('decorators' => array('FormElements')));
        $this->getDisplayGroup('db')->removeDecorator('DtDdWrapper');
        $this->getDisplayGroup('general')->removeDecorator('DtDdWrapper');
    }
    
    /**
     * зберігає дані форми у xml-файл
     */
    public function save() {
        if (!is_writable($this->_directory))
            throw new Exception("Директорія {$directory} не існує або недоступна для запису");
        if (!is_null($this->_fileName) && file_exists($this->_fileName))
            unlink($this->_fileName);
        $this->config = new Zend_Config(array(
            'date'      => $this->_date,
            'name'      => $this->name->getValue(),
            'alias'     => $this->alias->getValue(),
            'project'   => array(
                'path'      => $this->projectPath->getValue(),
                'framework' => $this->framework->getValue()),
            'tests'     => array(
                'path'      => $this->testsPath->getValue(),
                'framework' => $this->testsFramework->getValue()),
            'db'        => array(
                'adapter'   => $this->dbAdapter->getValue(),
                'host'      => $this->dbHost->getValue(),
                'username'  => $this->dbUsername->getValue(),
                'password'  => $this->dbPassword->getValue(),
            )
        ));
        
        $fileName = "{$this->_directory}/{$this->config->alias}_config.xml";
        $xml = new Zend_Config_Writer_Xml;
        $xml->write($fileName, $this->config);
    }
    
    /**
     * отримує список усіх піддеркторій проекта до другого рівня вкладеності
     */
    public function getDirectories($maxLevels = 4) {
        if ($maxLevels > 20)
            throw new Exception("Рівнів не може бути більше за 20");
        $startPath = rtrim($this->config->project->path, "/\\");
        $directories = array();
        $continue = true;
        for ($i=0, $path = $startPath; $i<$maxLevels && $continue; $i++) {
            $path .= "/*";
            $dirs = glob($path, GLOB_ONLYDIR);
            if (is_array($dirs) && count($dirs))
                $directories = array_merge($directories, $dirs);
            else
                $continue = false;
        }
        return $directories;
    }
    
    /**
     * отримує список усіх php-файлів проекта до другого рівня вкладеності
     */
    public function getFiles($directories = null) {
        $allFiles = array();
        $count = 0;
        if (is_null($directories))
            $directories = $this->getDirectories();
        foreach ($directories as $directory) {
            $files = glob($directory . '/*.php');
            if (is_array($files) && count($files))
                $allFiles = array_merge($allFiles, $files);
            $count++;
        }
        return $allFiles;
    }
}